package com.hongliang.chat.protocol;

import com.hongliang.chat.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

/**
 * 必须和
 *
 * @author Hongliang Zhu
 * @link{ LengthFieldBasedFrameDecoder } 一起使用，确保接到的 ByteBuf 消息是完整的
 * @create 2022-11-11 23:06
 */
@ChannelHandler.Sharable
@Slf4j
public class MessageCodecShareable extends MessageToMessageCodec<ByteBuf, Message> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> out) throws Exception {
        ByteBuf buf = ctx.alloc().buffer();

        // 4字节的魔数
        buf.writeBytes(new byte[]{1, 2, 3, 4});
        // 1个字节的版本号
        buf.writeByte(1);
        // 序列化的方式 0：jdk； 1：json
        buf.writeByte(0);
        //1字节的指令类型
        buf.writeByte(msg.getMessageType());

        // 4个字节的序列号
        buf.writeInt(msg.getSequenceId());
        // 无意义的字节填充
        buf.writeByte(0xff);

        // 填充内容
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream);
        oos.writeObject(msg);
        byte[] contents = byteArrayOutputStream.toByteArray();

        // 长度
        buf.writeInt(contents.length);
        // 写入内容
        buf.writeBytes(contents);

        out.add(buf);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int magicNum = in.readInt(); // 魔数
        byte version = in.readByte(); // 版本号
        byte serializerType = in.readByte(); // 序列化类型
        byte msgType = in.readByte(); // 消息类型
        int seqId = in.readInt();// 消息序列号
        in.readByte();
        int length = in.readInt();// 长度
        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);

        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
        Message msg = (Message) ois.readObject();

        log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, msgType, seqId, length);
        log.debug("{}", msg);
        out.add(msg);
    }
}
